Skip to main content

License - CS50x 2023

学习目标

  • 练习使用文件和文件指针
  • 进一步练习字符串和数组
  • 使用 debug50 进行调试
  • 使用 valgrind 检查内存泄漏

背景

假设你在一家开发人工智能车牌识别技术的公司工作。在开发你的技术时,你可能想使用实际的车牌号码作为测试数据。你有一个包含一些车牌号码的文本文件,你想对其进行分析,所以你首先尝试从该文本文件中读取并打印出车牌,以测试你的文件读取逻辑。但是当你运行你的程序时,只有最后一个号码被打印了 8 次!哪里出错了?

演示

开始

  1. 使用你的 GitHub 帐户登录 cs50.dev
  2. 单击终端窗口内部并执行 cd
  3. 执行 wget https://cdn.cs50.net/2022/fall/labs/4/license.zip,然后按 Enter 键,以便在你的 codespace 中下载一个名为 license.zip 的 zip 文件。请注意wget命令后URL之间的空格,以及其他任何字符错误!
  4. 现在执行 unzip license.zip 以创建一个名为 license 的文件夹。
  5. 你不再需要 ZIP 文件,因此你可以执行 rm license.zip 并在提示符下回复“y”,然后按 Enter 键。

实现细节

如果你打开 plates.txt 文件,你会注意到实际上有 8 个不同的车牌号码。分发代码中存在一些错误,导致这种情况发生。让我们首先浏览一下代码。

我们首先检查命令行参数,因为 argv[1] 应该是包含车牌的文本文件。然后我们创建一个长度为 7 的字符数组,因为车牌号码是 6 个 char,我们需要为 NUL 终止符保存空间。现在我们创建一个 char * 数组(字符指针,也称为 string),以存储 8 个车牌号码。我们创建一个指向外部文本文件的文件指针,创建一个变量来保存每个数组元素的索引,然后开始读取文件并将车牌号码保存到数组中。最后,为了测试我们是否正确地完成了此操作,我们打印出数组中的值。

但是,当我们编译并执行此代码时,显然有些问题。你需要进行适当的更正!

调试

仔细检查实际添加到数组中的数值。你可以使用 debug50 来查找分发代码中的错误。

  • 提示

    • 变量buffer中到底存储了什么内容,以至于它被赋给了plates数组的每一个元素?
    • 请注意,plates 数组是一个 char * 数组或字符串指针数组。
    • 那么,将字符数组buffer赋值给char *时,究竟发生了什么?

有没有更好的方法将车牌号码复制到 license 数组?

  • 更多提示

    • strcpy 在这里适用吗?
    • 如果将数据复制到指针,数据将去哪里?
    • 这里需要 malloc 吗?

检查内存泄漏

当你的程序运行正常后,请使用valgrind检查是否存在内存泄漏。

valgrind ./license plates.txt

你可能会得到类似这样的结果:

==24478== 堆内存摘要:
==24478== 程序退出时正在使用:528 字节,共 9 个块
==24478== 堆总计:分配 10 次,释放 1 次,共 4,624 字节
==24478==
==24478== 在第一条丢失记录中,确认有 56 字节分散在 8 个内存块中丢失
==24478== 位于 0x4848899:malloc (位于 /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==24478== 位于 0x109207:main (license.c:30)
==24478==
==24478== 在第二条丢失记录中,有 472 字节分散在 1 个内存块中仍然可访问
==24478== 位于 0x4848899:malloc (位于 /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==24478== 位于 0x4A086CD:__fopen_internal (iofopen.c:65)
==24478== 位于 0x4A086CD:fopen@@GLIBC_2.2.5 (iofopen.c:86)
==24478== 位于 0x1091CD:main (license.c:20)
==24478==
==24478== 内存泄漏摘要:
==24478== 确认丢失:56 字节,分散在 8 个内存块中
==24478== 间接丢失:0 字节,分散在 0 个内存块中
==24478== 可能丢失:0 字节,分散在 0 个内存块中
==24478== 仍然可访问:472 字节,分散在 1 个内存块中
==24478== 已忽略:0 字节,共 0 个块
==24478==
==24478== 要查看检测到的和被忽略的错误列表,请使用 -s 参数重新运行
==24478== 错误摘要:1 个错误,来自 1 个上下文(已忽略:0 个,来自 0 个上下文)

这里似乎存在两种需要解决的内存错误!

  • 提示

    • 您的行号可能不同,但请注意,第 30 行的 main 函数中似乎存在内存问题(与 malloc 有关?),以及第 20 行(与 fopen 相关的问题?)。分发代码可能缺少什么?

如何测试你的代码

你的程序应该产生如下示例所示的结果。

license/ $ ./license plates.txt
11ZT00
1KAD21
78ZZ01
99ZZ11
72ZZ21
98ZZ31
44ZW41
34ZZ51

你可以使用 check50 检查你的代码,check50 是 CS50 在你提交时用来测试你的代码的程序,通过在 $ 提示符下输入以下内容。但一定要自己测试一下!

check50 cs50/labs/2023/x/license

要评估你的代码风格,请在 $ 提示符下输入以下内容。

如何提交

无需提交!这是一个练习题。